using System;
using System.Collections.Generic;
using System.IO;

namespace BDDfyIt.Core
{
    public static class TextStoryParser
    {
        private const string Story = "Story";
        private const string AsA = "As a";
        private const string AsAn = "As an";
        private const string IWant = "I want";
        private const string SoThat = "So that";
        private const string Scenario = "Scenario";
        private const string Given = "Given";
        private const string When = "When";
        private const string Then = "Then";

        public static TextStory Parse(string storyFile)
        {
            if (string.IsNullOrEmpty(storyFile))
            {
                throw new Exception("Please specify a story to read");
            }
            var lines = File.ReadAllLines(storyFile);
            if (lines == null || lines.Length <= 0)
            {
                throw new Exception("The story is empty");
            }
            int lineNumber;
            var textStory = new TextStory
                                {
                                    Story = GetStory(lines, out lineNumber),
                                    Scenarios = GetScenarios(lines, lineNumber)
                                };
            return textStory;
        }

        private static Story GetStory(IList<string> lines, out int lineNumber)
        {
            var story = new Story();
            var storyLine = lines[0];
            lineNumber = 0;
            if (IsLineStartWithKeyword(storyLine, Story))
            {
                story.Name = ReadLineForGivenKeyword(storyLine, Story);
                lineNumber++;
            }
            
            for (var i = lineNumber; i < lines.Count; i++, lineNumber++)
            {
                if (IsLineStartWithKeyword(lines[i], AsA))
                {
                    story.AsA = ReadLineForGivenKeyword(lines[i], AsA);
                }
                else if (IsLineStartWithKeyword(lines[i], AsAn))
                {
                    story.AsA = ReadLineForGivenKeyword(lines[i], AsAn);
                }
                else if (IsLineStartWithKeyword(lines[i], IWant))
                {
                    story.IWantTo = ReadLineForGivenKeyword(lines[i], IWant);
                }
                else if (IsLineStartWithKeyword(lines[i], SoThat))
                {
                    story.SoThat = ReadLineForGivenKeyword(lines[i], SoThat);
                }
                else
                {
                    break;
                }
            }
            return story;
        }

        private static List<Scenario> GetScenarios(IList<string> lines, int lineNumber)
        {
            var scenarios = new List<Scenario>();
            while (lineNumber < lines.Count)
            {
                scenarios.Add(GetScenario(lines, lineNumber));
            }
            return scenarios;
        }

        private static Scenario GetScenario(IList<string> lines, int lineNumber)
        {
            var scenario = new Scenario { Givens = new List<string>(), Whens = new List<string>(), Thens = new List<string>() };
            var existingAttribute = string.Empty;
            var scenarioLine = lines[lineNumber];
            if (IsLineStartWithKeyword(scenarioLine, Scenario))
            {
                scenario.Name = ReadLineForGivenKeyword(scenarioLine, Scenario);
                lineNumber++;
            }
            for (var i = lineNumber; i < lines.Count; i++, lineNumber++)
            {
                if (IsLineStartWithKeyword(lines[i], Given))
                {
                    existingAttribute = Given;
                    scenario.Givens.Add(ReadLineForGivenKeyword(lines[i], Given));
                }
                else if (IsLineStartWithKeyword(lines[i], When))
                {
                    existingAttribute = When;
                    scenario.Whens.Add(ReadLineForGivenKeyword(lines[i], When));
                }
                else if (IsLineStartWithKeyword(lines[i], Then))
                {
                    existingAttribute = Then;
                    scenario.Thens.Add(ReadLineForGivenKeyword(lines[i], Then));
                }
                else
                {
                    if (string.Equals(existingAttribute, Given))
                    {
                        scenario.Givens.Add(ReadLineForGivenKeyword(lines[i], string.Empty));
                    }
                    else if (string.Equals(existingAttribute, When))
                    {
                        scenario.Whens.Add(ReadLineForGivenKeyword(lines[i], string.Empty));
                    }
                    else if (string.Equals(existingAttribute, Then))
                    {
                        scenario.Thens.Add(ReadLineForGivenKeyword(lines[i], string.Empty));
                    }
                }
            }
            return scenario;
        }

        private static bool IsLineStartWithKeyword(string line, string keyword)
        {
            if (string.IsNullOrEmpty(keyword))
            {
                return false;
            }
            return line.StartsWith(keyword) && line.IndexOf(keyword) != -1;
        }

        private static string ReadLineForGivenKeyword(string line, string keyword)
        {
            if (string.IsNullOrEmpty(keyword))
            {
                return line;
            }
            if (line.IndexOf(keyword) + keyword.Length + 1 < line.Length)
            {
                return line.Substring(line.IndexOf(keyword) + keyword.Length + 1);
            }
            return string.Empty;
        }
    }
}